/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkTcpUt.h"
#include "MkTcp/MkTcpClient.h"
#include "MkTcp/MkTcpServer.h"
#include "MkTcp/MkTcpSession.h"
#include "MkEvent/MkEventPool.h"
#include "MkEvent/MkEvent.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkLog.h"
#include "MkUtil/MkUtil.h"

class CMkTcpServerUt : public CMkTcpServer
{
public:
    CMkTcpServerUt(CMkEventPool* pEventPool, CMkTimer* pTimer, Uint32 MaxConnections);
    ~CMkTcpServerUt();
protected:
private:
    CMkTcpSession* CreateNewSession(CMkEvent *pEvent, CMkTimer* pTimer) override;
};

class CMkTcpSessionUt : public CMkTcpSession
{
public:
    CMkTcpSessionUt(CMkEvent* pEvent, CMkTimer* pTimer, CMkTcpServer* pServer);
    ~CMkTcpSessionUt();
protected:
private:
    Uint32 OnRecv() override;
};

CMkTcpServerUt::CMkTcpServerUt(CMkEventPool* pEventPool, CMkTimer* pTimer, Uint32 MaxConnections)
    : CMkTcpServer(pEventPool, pTimer, MaxConnections)
{

}

CMkTcpSession* CMkTcpServerUt::CreateNewSession(CMkEvent *pEvent, CMkTimer* pTimer)
{
    MkDebugLog("connected create new session\n");
    return new CMkTcpSessionUt(pEvent, pTimer, this);
}

CMkTcpServerUt::~CMkTcpServerUt()
{

}

CMkTcpSessionUt::CMkTcpSessionUt(CMkEvent* pEvent, CMkTimer* pTimer, CMkTcpServer* pServer)
    :CMkTcpSession(pEvent, pTimer, pServer)
{
}

CMkTcpSessionUt::~CMkTcpSessionUt()
{

}

Uint32 CMkTcpSessionUt::OnRecv()
{
    Uint8 pBuf[Len20K] = { 0 };
    Uint32 nToRead = Len20K;
    Uint32 ErrorCode = Recv(pBuf, nToRead);
    MkCheckErrorLog(ErrorCode, "recv failed\n");
    return Send(pBuf, nToRead);
}

void CMkTcpUt::SetUp()
{
    m_pEventPool = new CMkEventPool;
    m_pEventPool->Start(1);
    m_pTimer = new CMkTimer;
    m_pTcpServer = new CMkTcpServerUt(m_pEventPool, m_pTimer, 1);
    m_pTimer->StartTimerThread();
    Uint16 RandomPort = 0;
    while (1) {
        RandomPort = CMkUtil::GetRandomNumber() & 0xFFFF;
        if (NoneError == m_pTcpServer->StartServer(RandomPort)) {
            break;
        }
    }
    CMkThread::ThreadSleep(10);
}

void CMkTcpUt::TearDown()
{
    CMkThread::ThreadSleep(10);
    m_pTcpServer->StopServer();
    m_pTimer->StopTimerThread();
    m_pEventPool->Stop();
    MkDelete(m_pTcpServer);
    MkDelete(m_pEventPool);
    MkDelete(m_pTimer);
}

TEST_F(CMkTcpUt, TcpTest)
{
    Uint32 ErrorCode = NoneError;
    void* WaitHande = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    m_pTcpClient = new CMkTcpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [WaitHande, this](CMkTcpClient* pClient) {
        MkDebugLog("tcp client closed\n");
        SetEvent(WaitHande);
        pClient->DeleteLater();
        m_ClientLock.Lock();
        m_pTcpClient = nullptr;
        m_ClientLock.Unlock();
    });
    MkInfoLog("connect port:%d\n", m_pTcpServer->GetLocalPort());
    m_ClientLock.Lock();
    if (m_pTcpClient) {
        ErrorCode = m_pTcpClient->ConnectServer("127.0.0.1", m_pTcpServer->GetLocalPort(), [this]() {
            Uint32 ErrorCode = NoneError;
            Uint8 pBuf[Len2K] = { 0 };
            ErrorCode = m_pTcpClient->Send(pBuf, Len2K);
            EXPECT_EQ(NoneError, ErrorCode);
            ErrorCode = m_pTcpClient->Send(pBuf, Len1K);
            EXPECT_EQ(NoneError, ErrorCode);
            ErrorCode = m_pTcpClient->Send(pBuf, MtuSize);
            EXPECT_EQ(NoneError, ErrorCode);
            CMkBufferList Bufferlist;
            Bufferlist.Append(pBuf, 10, 1);
            ErrorCode = m_pTcpClient->Send(Bufferlist);
            EXPECT_EQ(NoneError, ErrorCode);
        });
        EXPECT_EQ(NoneError, ErrorCode);
    }
    m_ClientLock.Unlock();
    CMkThread::ThreadSleep(1000);  //wait connect success
    MkDebugLog("sleep end\n");

    m_ClientLock.Lock();
    if (m_pTcpClient) {
        ErrorCode = m_pTcpClient->Close();
    }

    m_ClientLock.Unlock();
    EXPECT_EQ(NoneError, ErrorCode);
    WaitForSingleObject(WaitHande, 0xFFFF);
    MkDebugLog("wait end\n");
    CloseHandle(WaitHande);
    ////test connect failed
    //void* WaitErrorHande = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    //m_pTcpClient = new CMkTcpClient(m_pEventPool->GetFreeEvent(), m_pTimer, [WaitErrorHande,this](CMkTcpClient* pClient) {
    //    MkDebugLog("connect failed close it\n");
    //    SetEvent(WaitErrorHande);
    //    pClient->DeleteLater();
    //    m_ClientLock.Lock();
    //    m_pTcpClient = nullptr;
    //    m_ClientLock.Unlock();
    //});
    //MkDebugLog("111\n");
    //m_ClientLock.Lock();
    //ErrorCode = m_pTcpClient->ConnectServer("127.0.0.1", 221);
    //m_ClientLock.Unlock();
    //EXPECT_EQ(NoneError, ErrorCode);
    //MkDebugLog("start begin\n");
    //WaitForSingleObject(WaitErrorHande, 0xFFFF);
    //MkDebugLog("wait end  2222\n");
    //CloseHandle(WaitErrorHande);
}